
package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.GregorianCalendar;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import exceptions.UPException;
import model.Job;
import model.ListManager;
import model.Park;

/**
 * VolunteerFrame class.
 * 
 * @author Doug Hutchens
 * @author Agari NLN
 * @author Sean Brown
 * @version 1.5
 */

@SuppressWarnings("serial")
public class VolunteerFrame extends JFrame {

	/** Default window dimension used for VolunteerFrame. */

	private static final Dimension DEFAULT_WINDOW = new Dimension(1000, 600);

	/** The region name to query on. */

	private static final String REGION_NAME = "Region";

	/** The district name to query on. */

	private static final String DISTRICT_NAME = "District";

	/** The park name to query on. */

	private static final String PARK_NAME = "Park";

	/** The ListManager private instance in frame. */

	private ListManager my_lm;

	/** The Available jobs table. */

	private JTable my_table;

	/** The Volunteer signed up jobs table. */

	private JTable my_jobs_table;

	/** The queried park that is selected. */

	private String my_selected_park;

	/** The queried region that is selected. */

	private String my_selected_region;

	/** The queried district that is selected. */

	private String my_selected_district;

	/** The menu bar that is used by frame. */

	private final UrbanParksMenuBar my_mmb;

	/** The parent welcomeFrame that is used. */

	private final WelcomeFrame my_welcome;

	/**
	 * Constructor for VolunteerFrame.
	 * 
	 * @param the_welcome
	 *            parent frame.
	 * @param the_lm
	 *            ListManager used in frame.
	 */

	public VolunteerFrame(final WelcomeFrame the_welcome,
			final ListManager the_lm) {
		super("Urban Parks: Volunteer");
		my_welcome = the_welcome;
		my_mmb = new UrbanParksMenuBar(my_welcome, this, the_lm);
		my_lm = the_lm;
		my_table = new JTable();
		my_jobs_table = new JTable();
		my_selected_park = "All";
		my_selected_region = "All";
		my_selected_district = "All";
	}

	/**
	 * Sets up all panels, preferences, and shows the frame on screen.
	 */
	public void start() {
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

		// create custom close operation
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				exit();
			}
		});

		UIManager.put("Panel.background", Color.WHITE);
		setPreferredSize(DEFAULT_WINDOW);
		setJMenuBar(my_mmb);
		add(header(), BorderLayout.NORTH);
		add(body(), BorderLayout.CENTER);
		pack();
		setLocationRelativeTo(getRootPane());
		setVisible(true);
	}

	/**
	 * Procedure used when exiting application.
	 */

	public void exit() {
		my_welcome.exitProcedure(this);
	}

	/**
	 * JPanel header to add to frame.
	 * 
	 * @return JPanel with user identification.
	 */

	private JPanel header() {
		JPanel result = new JPanel();
		JLabel user_label = new JLabel("Welcome "
				+ my_lm.getCurrentUser().getName() + "!", JLabel.LEFT);
		user_label.setFont(GUIUtil.largerFont(result));
		user_label.setHorizontalAlignment(JLabel.LEFT);
		result.add(user_label);
		return result;
	}

	/**
	 * JPanel body that consists of JTables of available and user jobs.
	 * 
	 * @return JPanel with tables.
	 */

	private JPanel body() {
		JPanel body_panel = new JPanel(new GridLayout(2, 1));

		JPanel user_jobs = new JPanel(new BorderLayout());
		user_jobs.add(getMyJobLabel(), BorderLayout.NORTH);
		user_jobs.add(/* new JScrollPane( */getMyJobs()/*
													 * ,JScrollPane.
													 * VERTICAL_SCROLLBAR_AS_NEEDED
													 * , JScrollPane.
													 * HORIZONTAL_SCROLLBAR_AS_NEEDED
													 * )
													 */, BorderLayout.CENTER);

		JPanel all_jobs = new JPanel(new BorderLayout());
		all_jobs.add(getMyAvailableJobLabel(), BorderLayout.NORTH);
		all_jobs.add(/* new JScrollPane( */getAvailableJobs()/*
															 * ,JScrollPane.
															 * VERTICAL_SCROLLBAR_AS_NEEDED
															 * , JScrollPane.
															 * HORIZONTAL_SCROLLBAR_AS_NEEDED
															 * )
															 */,
				BorderLayout.CENTER);

		body_panel.add(user_jobs);
		body_panel.add(all_jobs);
		return body_panel;
	}

	/**
	 * Updates the table model from user browsing jobs.
	 * 
	 * @param the_box
	 *            JComboBox selected.
	 */

	private void updateModel(JComboBox the_box) {

		if (the_box.getName().equals(PARK_NAME)) {
			my_selected_park = the_box.getSelectedItem().toString();
		} else if (the_box.getName().equals(REGION_NAME)) {
			my_selected_region = the_box.getSelectedItem().toString();
		} else if (the_box.getName().equals(DISTRICT_NAME)) {
			my_selected_district = the_box.getSelectedItem().toString();
		}

		Collection<Job> jobs = getQueriedJobs(my_lm.getJobs(),
				my_selected_park, my_selected_region, my_selected_district);

		VolunteerTableModel model = new VolunteerTableModel(jobs, true, my_lm);

		my_table.setModel(model);
		TableColumn column = my_table.getColumnModel().getColumn(13);
		final JCheckBox checkBox = new JCheckBox();
		checkBox.setHorizontalAlignment(JCheckBox.CENTER);
		column.setCellEditor(new CheckBoxEditor(checkBox, my_table, my_lm,
				jobs, my_jobs_table));

		column.setCellRenderer(new DefaultTableCellRenderer() {
			public Component getTableCellRendererComponent(JTable my_table,
					Object value, boolean isSelected, boolean hasFocus,
					int row, int column) {
				if (value instanceof Boolean) {
					checkBox.setSelected(((Boolean) value).booleanValue());
				}
				return checkBox;
			}

		});

		my_table.revalidate();
	}

	/**
	 * Gets the available jobs for a user.
	 * 
	 * @return JPanel with JTable of existing jobs.
	 */

	private JPanel getAvailableJobs() {
		JPanel result = new JPanel(new BorderLayout());

		result.add(getComboBoxes(), BorderLayout.NORTH);
		my_table = new JTable();
		my_table.setFont(GUIUtil.mediumFont(my_table));

		Collection<Job> jobs = getQueriedJobs(my_lm.getJobs(),
				my_selected_park, my_selected_region, my_selected_district);

		VolunteerTableModel model = new VolunteerTableModel(jobs, true, my_lm);
		my_table.setModel(model);

		TableColumn column = my_table.getColumnModel().getColumn(13);
		final JCheckBox checkBox = new JCheckBox();
		checkBox.setHorizontalAlignment(JCheckBox.CENTER);
		column.setCellEditor(new CheckBoxEditor(checkBox, my_table, my_lm,
				jobs, my_jobs_table));
		column.setCellRenderer(new DefaultTableCellRenderer() {
			public Component getTableCellRendererComponent(JTable my_table,
					Object value, boolean isSelected, boolean hasFocus,
					int row, int column) {
				if (value instanceof Boolean) {
					checkBox.setSelected(((Boolean) value).booleanValue());
				}
				return checkBox;
			}

		});
		

		my_table.setName("Available Jobs");
		my_table.setBackground(Color.WHITE);
		JTableHeader header = my_table.getTableHeader();
		header.setBackground(Color.GREEN);
		my_table.add(header);
		result.add(new JScrollPane(my_table), BorderLayout.CENTER);
		my_table.revalidate();
		return result;
	}

	/**
	 * Gets the queried jobs based on selection.
	 * 
	 * @param the_jobs
	 *            all jobs.
	 * @param the_park
	 *            that is selected.
	 * @param the_region
	 *            that is selected.
	 * @param the_district
	 *            that is selected.
	 * @return Collection<Jobs> based on browsing selection.
	 */

	private Collection<Job> getQueriedJobs(Collection<Job> the_jobs,
			String the_park, String the_region, String the_district) {
		int count = 0;
		Collection<Job> result = new ArrayList<Job>();
		

		for (Job j : the_jobs) {
			count = 0;
			Park p = null;
			try {
				p = my_lm.findPark(j.getParkId());
			} catch (final UPException e) {
				GUIUtil.errorMessage(this, e.getMessage());
			}

			if ((the_park.equals("All")) || (the_park.equals(p.getName()))) {
				count++;
			}

			if ((the_region.equals("All"))
					|| (the_region.equals(p.getRegion()))) {
				count++;
			}

			if ((the_district.equals("All"))
					|| (the_district.equals(p.getDistrict()))) {
				count++;
			}
			// Make sure the job has not already passed
			if (count == 3 && j.getEndTime().after((new GregorianCalendar()))) {
				result.add(j);
			}
		}

		return result;
	}

	/**
	 * Gets the JPanel consisting of JComboBoxes.
	 * 
	 * @return JPanel with comboBoxes.
	 */

	private JPanel getComboBoxes() {
		JPanel result = new JPanel(new FlowLayout());
		result.add(new JLabel("Park:"));
		result.add(getComboBox(PARK_NAME));
		result.add(new JLabel(""));
		result.add(new JLabel(""));
		result.add(new JLabel("District:"));
		result.add(getComboBox(DISTRICT_NAME));
		result.add(new JLabel(""));
		result.add(new JLabel(""));
		result.add(new JLabel("Region:"));
		result.add(getComboBox(REGION_NAME));
		return result;
	}

	/**
	 * gets the jobs that a volunteer is signed up for.
	 * 
	 * @return JPanel with table of jobs associated with user.
	 */

	private JPanel getMyJobs() {
		JPanel result = new JPanel(new BorderLayout());
		my_jobs_table = new JTable();
		my_jobs_table.setFont(GUIUtil.mediumFont(my_jobs_table));
		Collection<Job> jobs = my_lm.getUserJobs();
		VolunteerTableModel model = new VolunteerTableModel(jobs, false, my_lm);
		my_jobs_table.setModel(model);
		my_jobs_table.setName("My Jobs");
		my_jobs_table.setBackground(Color.WHITE);

		JTableHeader header = my_jobs_table.getTableHeader();
		header.setBackground(Color.GREEN);
		my_jobs_table.add(header);

		result.add(new JScrollPane(my_jobs_table), BorderLayout.CENTER);
		return result;

	}

	/**
	 * Gets a JLabel with user jobs.
	 * 
	 * @return JLabel to use when displaying user jobs.
	 */

	private JLabel getMyJobLabel() {
		JLabel result = new JLabel("My Jobs");
		result.setHorizontalAlignment(JLabel.LEFT);

		return result;
	}

	/**
	 * Gets a JLabel for available jobs to browse.
	 * 
	 * @return JLabel with title to browse jobs.
	 */

	private JLabel getMyAvailableJobLabel() {
		JLabel result = new JLabel("Browse Jobs");
		result.setHorizontalAlignment(JLabel.LEFT);

		return result;
	}

	/**
	 * Gets a JCombo box with built in jobs.
	 * 
	 * @param the_item
	 *            string to build values from.
	 * @return JComboBox with distinct items.
	 */

	private JComboBox getComboBox(String the_item) {
		JComboBox result = new JComboBox();
		result.addItem("All");

		try {
			for (String name : getDistinctItem(the_item)) {
				result.addItem(name);
				result.setName(the_item);
			}
		} catch (final UPException e) {
			GUIUtil.errorMessage(this, e.getMessage());
		}

		result.addItemListener(new ItemListener() {

			@Override
			public void itemStateChanged(ItemEvent e) {
				JComboBox bc = (JComboBox) e.getSource();

				if (e.getStateChange() == ItemEvent.SELECTED) {
					updateModel(bc);
				}
			}

		});

		return result;
	}

	/**
	 * Gets a list of distinct items to add to a JComboBox.
	 * 
	 * @param the_item
	 *            to get distinct items.
	 * @return Collection<String> to add.
	 * @throws UPException
	 */

	private Collection<String> getDistinctItem(String the_item)
			throws UPException {
		Collection<String> result = new ArrayList<String>();

		for (Job j : my_lm.getJobs()) {

			Park park = my_lm.findPark(j.getParkId());

			if (the_item.equalsIgnoreCase(DISTRICT_NAME)) {
				if (!isDistinctItemInLlst(result, park.getDistrict())) {
					result.add(park.getDistrict());
				}

			} else if (the_item.equalsIgnoreCase(REGION_NAME)) {
				if (!isDistinctItemInLlst(result, park.getRegion())) {
					result.add(park.getRegion());
				}

			} else if (the_item.equals(PARK_NAME)) {
				if (!isDistinctItemInLlst(result, park.getName())) {
					result.add(park.getName());
				}
			}
		}

		return result;
	}

	/**
	 * Checks if the string is already in list.
	 * 
	 * @param the_list
	 *            of all strings.
	 * @param the_item
	 *            string to check.
	 * @return boolean whether the string exists or not.
	 */

	private boolean isDistinctItemInLlst(Collection<String> the_list,
			                             String the_item) {
		boolean result = false;

		for (String item : the_list) {
			if (the_item.equals(item)) {
				result = true;
			}
		}

		return result;
	}

}
